#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#include <json-c/json.h>

#include "custom.h"
#include "msg.h"
#include "ice_client.h"

static char *g_period_msg = NULL;
static char *g_id = "123456";
static char *g_resp_msg = "OK";
static long long g_seq = 0;

int device_type = 0;

static char* GenRandomString(int length)
{
	int flag, i;
	char* str;
	
	srand((unsigned) time(NULL ));
	
	if ((str = (char*) malloc(length)) == NULL )
	{
		printf("Malloc failed!\n");
		return NULL ;
	}
 
	for (i = 0; i < length - 1; i++)
	{
		flag = rand() % 3;
		switch (flag)
		{
			case 0:
				str[i] = 'A' + rand() % 26;
				break;
			case 1:
				str[i] = 'a' + rand() % 26;
				break;
			case 2:
				str[i] = '0' + rand() % 10;
				break;
			default:
				str[i] = 'x';
				break;
		}
	}
	
	str[length - 1] = '\0';
	
	return str;
}

static void MkPeriodMsg()
{
	g_id = GenRandomString(32);
	printf("get random id: %s\n", g_id);

	struct json_object *object = json_object_new_object(); 
	
	json_object_object_add(object, "event", json_object_new_int(EVENT_TYPE_HEART_BEAT));  
	json_object_object_add(object, "id", json_object_new_string(g_id));
	json_object_object_add(object, "type", json_object_new_int(device_type));  

	g_period_msg = strdup(json_object_to_json_string(object));
	
	printf("-----------json info ---------------------------\n");  
	printf("g_period_msg: %s\n", g_period_msg);  
	printf("-----------json info ---------------------------\n");  

	json_object_put(object);
}

int ParseEvent(char *json_data, 
					char *data, 
					int max_data_size,
					char *peer_id,
					int max_id_size)
{
	json_object *obj;
	obj = json_tokener_parse(json_data);

	json_object *event_object = NULL; 
	json_object *data_object = NULL;
	json_object *id_object = NULL;

	event_object =  json_object_object_get(obj, "event");
	if (!event_object)
	{
		printf("ParseEvent failed\n");
		
		json_object_put(obj);
		
		return -1;
	}

	int event = json_object_get_int(event_object);

	printf("ParseEvent, EventId=%d\n", event);

	data_object = json_object_object_get(obj, "data");
	if (data_object)
	{
		const char *str = json_object_get_string(data_object);
		int len = strlen(str);
		strncpy(data, str, len>max_data_size?max_data_size:len);
		printf("ParseEvent, data: %s\n", data);
	}

	id_object = json_object_object_get(obj, "peer_id");
	if (id_object)
	{
		const char *str = json_object_get_string(id_object);
		int len = strlen(str);
		strncpy(peer_id, str, len>max_id_size?max_id_size:len);
		printf("ParseEvent, peer_id: %s\n", peer_id);
	}

	json_object_put(obj);

	return event;
}

void InitCommJsonMsg()
{
	MkPeriodMsg();
}

char *GetRespMsg()
{
	return g_resp_msg;
}

char *GetPeriodMsg()
{
	return g_period_msg;
}

char *GetID()
{
	return g_id;
}

//
char *CreateEvent(event_type_e eventId, char *id, char *peer_id, char *msg)
{
	if (!id)
	{
		return NULL;
	}
		
	struct json_object *object = json_object_new_object(); 
	
	json_object_object_add(object, "event", json_object_new_int(eventId)); 

	json_object_object_add(object, "seq", json_object_new_int64(g_seq++)); 

	json_object_object_add(object, "id", json_object_new_string(id));

	json_object_object_add(object, "type", json_object_new_int(device_type));  

	if (msg)
	{
		json_object_object_add(object, "msg", json_object_new_string(msg)); 
	}

	if (peer_id)
	{
		json_object_object_add(object, "peer_id", json_object_new_string(peer_id));
	}

	char *buff = strdup(json_object_to_json_string(object));

	json_object_put(object);

	printf("CreateEvent, json: %s\n", buff);

	return buff;
}

void QueryDevList()
{
	MsgNode *comm_msg = (MsgNode *)malloc(sizeof(MsgNode));
	comm_msg->cmd_.seq_ = 0;
	comm_msg->cmd_.msg_ = CreateEvent(EVENT_TYPE_QUERY_DEVICE, GetID(), NULL, NULL);
	PushBack2SndQueue(comm_msg);
}

void ReqConn(char *peer_id, char *ice)
{
	MsgNode *comm_msg = (MsgNode *)malloc(sizeof(MsgNode));
	comm_msg->cmd_.seq_ = 0;
	comm_msg->cmd_.msg_ = CreateEvent(EVENT_TYPE_CONN_REQ, GetID(), peer_id, ice);
	PushBack2SndQueue(comm_msg);
}

void RespConn(char *peer_id, char *ice)
{
	MsgNode *comm_msg = (MsgNode *)malloc(sizeof(MsgNode));
	comm_msg->cmd_.seq_ = 0;
	comm_msg->cmd_.msg_ = CreateEvent(EVENT_TYPE_CONN_RESP, GetID(), peer_id, ice);
	PushBack2SndQueue(comm_msg);
}

void HandleConnResp(char *peer_ice)
{
	char *buf = strdup(peer_ice);
	write(GetICEWritePipe(), (void *)buf, strlen(peer_ice));
}

void HandleDevList(char *dev_list)
{
	char *peer_id = NULL;

	if (dev_list && dev_list[0] != '\0')
	{
		//printf("HandleDevList, strlen(dev_list) = %d\n", (int)strlen(dev_list));
		
		char *s1 = strstr(dev_list, ",");
		if (s1)
		{
			int len = s1 - dev_list;
			peer_id = (char *)malloc(len);
			strncpy(peer_id, dev_list, len);
		}
		else
		{
			peer_id = strdup(dev_list);
		}
	}

	printf("HandleDevList, peer device id is: %s\n", peer_id);

	if (peer_id)
	{
		ice_config *cfg = (ice_config *)malloc(sizeof(ice_config));

		memset(cfg, 0, sizeof(ice_config));

		char *turn_server = getenv("TURN_SERVER");
		char *turn_port_str = getenv("TURN_PORT");

		if (!turn_server)
		{
			turn_server = "stunserver.org";
		}

		if (!turn_port_str)
		{
			turn_port_str = "3478";
		}

		printf("getenv, turn_server:%s, turn_port_str:%s\n", turn_server, turn_port_str);

		strncpy(cfg->ip, turn_server, 
			strlen(turn_server)>sizeof(cfg->ip)?sizeof(cfg->ip):strlen(turn_server));
		
		cfg->port = atoi(turn_port_str);
		cfg->action = 1;
		cfg->peer_ice = NULL;
		cfg->peer_id = peer_id;

		StartICE(cfg);
	}
	else
	{
		sleep(5);
		QueryDevList();
	}
}

void HandleConnReq(char *peer_ice, char *peer_id)
{
	ice_config *cfg = (ice_config *)malloc(sizeof(ice_config));

	memset(cfg, 0, sizeof(ice_config));

	char *turn_server = getenv("TURN_SERVER");
	char *turn_port_str = getenv("TURN_PORT");

	if (!turn_server)
	{
		turn_server = "stunserver.org";
	}
	
	if (!turn_port_str)
	{
		turn_port_str = "3478";
	}
	
	printf("==== getenv, turn_server:%s, turn_port_str:%s\n", turn_server, turn_port_str);

	strncpy(cfg->ip, turn_server, 
			strlen(turn_server)>sizeof(cfg->ip)?sizeof(cfg->ip):strlen(turn_server));
		
	cfg->port = atoi(turn_port_str);
	
	cfg->action = 0;
	cfg->peer_ice = strdup(peer_ice);
	cfg->peer_id = strdup(peer_id);

	StartICE(cfg);
}

/////////////////////////////////////////////////////////////////////////////////////////
////for test
static void *TestPipe(void *arg)
{
	sleep(5);
	
	int i = 0;
	
	while(1)
	{
		MsgNode *comm_msg = (MsgNode *)malloc(sizeof(MsgNode));
		comm_msg->cmd_.seq_ = i++;
		char msg[256] = {0};
		sprintf(msg, "This is msg %d", i);
		comm_msg->cmd_.msg_ = CreateEvent(i+100, "a23ce5ab2f99877ee", NULL, msg);
		PushBack2SndQueue(comm_msg);

		sleep(2);
	}

	return NULL;
}

int StartTestSnd()
{
	pthread_t tid;
	int ret = pthread_create(&tid, NULL, TestPipe, NULL);
	if (ret < 0)
	{
		perror("pthread_create");
		exit(-1);
	}

	return 0;
}

